#include "deamon/daemon_process.h"
#include "thirdparty/log.h"
#include <stdlib.h>  //内存分配和释放
#include "string.h"
#include "sys/types.h"
#include "sys/wait.h"
#include "signal.h"

/// @brief 初始化一个进程的相关参数 
/// @param dp 进程对象指针
/// @param part 进程对象的第2个运行参数
/// @return 成功返回0  失败返回-1
int daemon_process_init(DaemonProcess *dp, const char *part)
{
    dp->exec = "/usr/bin/gateway";  //设置子进程要执行的命令路径
    dp->argv[0] = dp->exec;         //执行程序的第一个参数  一般都执行文件的路径
    //开辟空间
    dp->argv[1] = malloc(strlen(part) + 1);
    //判断成功没有
    if(!dp->argv)
    {
        //失败
        log_warn("mem malloc fail");
        return -1;
    }  
    dp->argv[1] = part;           //第二个参数
    dp->argv[2] = NULL;           //需要一个null封口
    dp->pid = -1;     //没有创建进程默认为-1
    return 0;     
}

/// @brief 启动一个进程
/// @param dp 进程对象指针
/// @return 成功返回0  失败返回-1
int daemon_process_start(DaemonProcess *dp)
{
    //这是父进程进入 并且以及fork过l  不然回是-1
   if(dp->pid > 0)
   {
     //判断有没有进程执行  WNOHANG不阻塞 没有直接返回
    int result = waitpid(dp->pid,NULL,WNOHANG);
    //如果成功等待到一个子进程结束，则返回该子进程的 PID。
    //如果没有子进程结束或者根据 options 参数没有子进程符合条件，则返回 0。
    //如果发生错误，则返回 -1，并且设置 errno 来指示错误的原因。
    if(result == 0)
    {
        //说明有 程序在运行
        return -1;
    }
   }
     log_trace("Gateway %s starting...", dp->argv[1]);
    //这表示还没进程在运行  fork会复制一个一样的子进程  唯一不同就算pid
    //在父进程中fork()他返回子进程的pid    在子进程中返回0
    dp->pid =  fork();
    if(dp->pid == -1)
    {
        //说明复制进程失败
        log_warn("daemon_process: fork fail");
        return -1;
    }

    if(dp->pid == 0)
    {
        //说明这个是子进程
        //让这个子进程执行别的程序不会再相信下举行执行
        //dp->exec 那个程序的路径 dp->arg程序的所以参数    __environ环境变量
        if(execve(dp->exec,dp->argv,__environ) < 0)
        {
            //失败
            log_warn("daemon_process: execve fail");
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}

/// @brief 停止一个进程
/// @param dp 进程对象指针
/// @return 成功返回0  失败返回-1
int daemon_process_stop(DaemonProcess *dp)
{
    //判断是一个以及frok过了的父进程不然pid = -1
    if(dp->pid > 0)
    {
        //杀死一个子进程  dp->pid 子进程的pid SIGTERM停止信号
        kill(dp->pid, SIGTERM);
        //回收子进程
        waitpid(dp->pid,NULL,0);
        //重置pid  当他等于-1  向当于我们自己约定了的 没有创建子进程
        //如果创建了 frok 后父进程 dp->pid 这里是子进程的pid   
        //子进程的pid  会是0
        dp->pid = -1;
    }
    return 0;
}


/// @brief 释放进程对象内存
/// @param dp 
/// @return 
int daemon_process_free(DaemonProcess *dp)
{
    free(dp->argv[1]);
    return 0;
}
